Skip to content

docs(cif): CIF output correctness design doc (#68, #238)#303

Open
manzuoni-astera wants to merge 1 commit into
diff-use:mainfrom
manzuoni-astera:michaelanzuoni/cif-output-design
Open

docs(cif): CIF output correctness design doc (#68, #238)#303
manzuoni-astera wants to merge 1 commit into
diff-use:mainfrom
manzuoni-astera:michaelanzuoni/cif-output-design

Conversation

@manzuoni-astera

@manzuoni-astera manzuoni-astera commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Summary

Both #68 and #238 are facets of the same "fix our CIF outputs" problem, and Marcus asked (on #238) for a design doc to catalog and consolidate the work before we start hacking at it. This adds docs/design/cif-output-correctness.md.

I investigated the code first rather than guess — key findings:

The doc lays out a phased plan (native header copy → Protenix chain-ID fix, scoped vs. general multi-chain → entity generation → retire the patch), with the cross-model differences tabulated and every claim cited to file:line.

This PR is docs-only — no code changes. It's the "catalog + plan" step; the phased fixes (and a Phase-0 regression test pinning atom_site.id uniqueness against a biotite bump) are follow-ups once we agree the direction. Flagging the open questions in §7 for @marcuscollins.

Refs #68, #238.

Summary by CodeRabbit

  • Documentation
    • Added a new design document outlining current mmCIF output correctness gaps and a phased plan to improve output consistency.
    • Describes known issues with chain-ID handling, missing standard header information, and incomplete entity-related metadata in generated files.
    • Summarizes the current workaround approach and the intended path toward removing it in favor of native handling.

…se#238)

Consolidates the CIF-output issues Marcus asked to catalog: per-model chain-ID
handling (RF3/Boltz preserve, Protenix reinvents), the entity/header gaps in the
native writers, and the silent multi-chain remap hazard in patch_output_cif_files.
Documents that atom_site.id uniqueness (#68a) is already satisfied by the pinned
biotite 1.4.0 (verified), narrowing diff-use#68 scope to entities + header, and lays out a
phased plan toward retiring the post-processing patch.

Refs diff-use#68, diff-use#238.
Copilot AI review requested due to automatic review settings July 8, 2026 17:44
@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5fe5b0e9-a25b-4694-9407-a6143cb5ee89

📥 Commits

Reviewing files that changed from the base of the PR and between 38f244a and 3f82f58.

📒 Files selected for processing (1)
  • docs/design/cif-output-correctness.md

📝 Walkthrough

Walkthrough

Adds a new design/RFC document, docs/design/cif-output-correctness.md, describing missing correctness components in native mmCIF outputs (atom_site.id uniqueness, entity/entity_poly, header categories, Protenix chain-ID mismatches), current behavior, patch script analysis, and a phased migration plan.

Changes

Design Documentation

Layer / File(s) Summary
CIF output correctness RFC
docs/design/cif-output-correctness.md
New document detailing current mmCIF output gaps across RF3/Boltz/Protenix, the patch_output_cif_files.py behavior including a disabled multi-chain guard, and a phased plan (Phase 0–4) to add native header carry-over, fix chain IDs, generate entity/entity_poly, and retire the patch.

Estimated code review effort: 1 (Trivial) | ~5 minutes

Suggested reviewers: marcuscollins

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly states this is a CIF output correctness design doc and matches the docs-only change.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a design/RFC document to catalog current mmCIF output correctness gaps across model wrappers (RF3/Boltz/Protenix), relate them to #68 and #238, and propose a phased plan to remove reliance on scripts/patch_output_cif_files.py while avoiding silent multi-chain evaluation corruption.

Changes:

  • Introduces a new design doc describing the current CIF write path and requirement status for atom_site.id, entities, and header carry-over.
  • Documents the Protenix chain-ID mismatch root cause and the specific silent-corruption hazard in patch_output_cif_files.py when the guard is disabled.
  • Proposes a phased remediation plan (header carry-over → Protenix chain IDs → entity generation → retire patch) with cited code references.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +29 to +31
| **RF3** | `InferenceInput.from_atom_array(atom_array, chain_info=…)`; `model_aa = pipeline_output["atom_array"].copy()` (`models/rf3/wrapper.py:340,402`) | **Preserved** from the input AtomArray — no lossy round-trip |
| **Boltz** | YAML carries per-chain `id: {chain_id}` (`models/boltz/wrapper.py:479,493`); echoed back and decoded (`models/boltz/wrapper.py:207`) | **Preserved** |
| **Protenix** | Structure → chain-less JSON → `SampleDictToFeatures(json).get_feature_dict()` rebuilds the AtomArray (`models/protenix/wrapper.py:393`) | **Reinvented** (A, B, C… by entity/copy order) |
Comment on lines +33 to +37
Protenix is the outlier: `structure_to_protenix_json()` (`models/protenix/structure_processing.py:515`)
builds an AlphaFold3-style JSON whose entity dicts have **no per-chain `id` slot** — chains
are collapsed into entities with a copy `count` (`structure_processing.py:660`). The real
chain IDs are only set on the *input-side* array (`structure_processing.py:566`,
`set_annotation("label_asym_id", …)`), which is discarded; the array that reaches output
Comment on lines +38 to +40
(`models/protenix/wrapper.py:478` `model_aa = cast(AtomArray, atom_array_protenix)`) has
Protenix's invented letters. That array is what gets written to `refined.cif`
(`utils/guidance_script_utils.py:325-342`).
Comment on lines +46 to +50
- `save_everything` → `refined.cif`: `utils/guidance_script_utils.py:339-342` (ensemble becomes a
multi-model `AtomArrayStack` at `:331-337`).
- `save_structure_to_cif`: `utils/atom_array_utils.py:183-185` (generic; used by synthetic-density
and altloc-fixed temp CIFs).
- Trajectory CIFs: `utils/guidance_script_utils.py:123,148` via biotite `save_structure` (a
Comment on lines +53 to +54
The input structure is read with atomworks `parse(...)` (`guidance_script_utils.py:236`), which
returns only the `AtomArray` — **the input CIF's header categories are dropped before writing.**
Comment on lines +75 to +77
into the template so its **header is preserved** (`:233`) → reconcile `pdbx_poly_seq_scheme`
→ overwrite `atom_site.id` with a unique `arange` (`:245`) → ensure `occupancy`/`B_iso`
columns → write `<stem>-patched.cif`.
Comment on lines +123 to +127
correspondence (`eval/structure_utils.py:191`) before writing, then re-enable the
`patch_output_cif_files.py` guard for those cases. Caveat: the reconciler keys on **sorted
chain position**, not label (`utils/atom_array_utils.py:604-635`,
`utils/atom_reconciler.py:64-107`), so this is only correct when Protenix's sorted chain
order matches the reference's.
Comment on lines +153 to +156
- Protenix chain loss: `models/protenix/structure_processing.py:515,566,660`; `models/protenix/wrapper.py:393,478,505`
- Chain-ID preservation (RF3/Boltz): `models/rf3/wrapper.py:340,402`; `models/boltz/wrapper.py:207,479,493`
- Writers: `utils/guidance_script_utils.py:236,325-342,123,148`; `utils/atom_array_utils.py:183-185`
- Reconciler / position-based matching: `eval/structure_utils.py:191`; `utils/atom_reconciler.py:64-107`; `utils/atom_array_utils.py:604-635`
Comment on lines +101 to +103
3. **No cross-model entity bookkeeping** — only Protenix carries `label_entity_id`
(`models/protenix/structure_processing.py:241,281,340`); Boltz/RF3 do not, so there is no
uniform place to build `entity`/`entity_poly`.
Comment on lines +61 to +62
| **(b) entity / `entity_id`** | **Missing.** No `entity`/`entity_poly` category is ever constructed; `set_structure` only emits `label_entity_id` if the array carries that annotation. | `guidance_script_utils.py:339-342`; patch injects it at `patch_output_cif_files.py:220-231` |
| **(c) header (cell, symmetry, struct, entity_poly, pdbx_poly_seq_scheme, …)** | **Missing.** Only the custom `sampleworks` metadata block is written; everything else was dropped at parse time. | `guidance_script_utils.py:341`; patch recovers header from the template at `patch_output_cif_files.py:233` |
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants